/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 */

package com.huawei.housekeeper.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.collect.Lists;
import com.huawei.housekeeper.config.ThreadPoolProperty;
import com.huawei.housekeeper.constants.DeletedFlagEnum;
import com.huawei.housekeeper.constants.NumberConstant;
import com.huawei.housekeeper.constants.RabbitMqTopicConfig;
import com.huawei.housekeeper.constants.TaskOrderAction;
import com.huawei.housekeeper.controller.converter.TaskConverter;
import com.huawei.housekeeper.controller.request.*;
import com.huawei.housekeeper.controller.response.MyTaskDetailVo;
import com.huawei.housekeeper.controller.response.MyTaskListVo;
import com.huawei.housekeeper.controller.response.TaskDetailVo;
import com.huawei.housekeeper.controller.response.TaskPageListVo;
import com.huawei.housekeeper.dao.entity.Task;
import com.huawei.housekeeper.dao.mapper.TaskMapper;
import com.huawei.housekeeper.entity.MessageServiceEntity;
import com.huawei.housekeeper.entity.TaskMessageEntity;
import com.huawei.housekeeper.enums.ErrorCode;
import com.huawei.housekeeper.enums.OrderTaskEnum;
import com.huawei.housekeeper.exception.Assert;
import com.huawei.housekeeper.feign.request.UpdateOrderDto;
import com.huawei.housekeeper.result.ListRes;
import com.huawei.housekeeper.service.ITaskService;
import com.huawei.housekeeper.utils.ApplicationContextUtil;
import com.huawei.housekeeper.utils.JwtTokenUtil;
import com.huawei.housekeeper.utils.MessageServiceUtil;
import com.huawei.housekeeper.utils.TokenUtil;
import com.huawei.saashousekeeper.context.TenantContext;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * 任务表服务类
 *
 * @author jwx1116205
 * @since 2022-03-02
 */
@Log4j2
@Service
public class TaskServiceImpl implements ITaskService {
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    private ThreadPoolProperty threadPoolProperty;

    @Autowired
    private TaskMapper taskMapper;

    @Autowired
    private MessageServiceUtil messageServiceUtil;

    @Autowired OrderService orderService;

    @Autowired
    private TokenUtil tokenUtil;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    /**
     * 查询个人已接任务详情，除了用户名称和电话
     *
     * @param myTaskDetailDto 任务Dto
     * @return 任务详情
     */
    @Override
    public MyTaskDetailVo myTaskDetailDto(MyTaskDetailDto myTaskDetailDto) {
        LambdaQueryWrapper<Task> selectQuery = Wrappers.lambdaQuery();
        selectQuery.eq(Task::getId, myTaskDetailDto.getId());
        selectQuery.eq(Task::getDeleteFlag, DeletedFlagEnum.SERVICE_FLAGE_UNDELETED.getCode());
        Task taskOne = Optional.ofNullable(taskMapper.selectOne(selectQuery)).orElseGet(() -> {
            return new Task();
        });
        MyTaskDetailVo myTaskDetailVo = TaskConverter.INSTANCE.toMyTaskDetailVo(taskOne);
        myTaskDetailVo.setImgSrc(taskMapper.queryImageDetailByTaskId(taskOne.getId()));
        return myTaskDetailVo;
    }

    /**
     * 查询个人已接任务
     *
     * @return 个人已接任务列表
     */
    @Override
    public ListRes<MyTaskListVo> myTaskListDto(PageQueryMyTaskDto pageQueryMyTaskDto) {
        LambdaQueryWrapper<Task> select = Wrappers.lambdaQuery();
        select.eq(Task::getEmployeeId, tokenUtil.getUidFromHeader());
        select.eq(Task::getDeleteFlag, DeletedFlagEnum.SERVICE_FLAGE_UNDELETED.getCode());
        select.eq(Task::getTaskStatus, TaskOrderAction.TASK_ORDER_ACCEPT.getAction());
        select.like(StringUtils.isNotEmpty(pageQueryMyTaskDto.getCustomerName()), Task::getCustomerName,
                pageQueryMyTaskDto.getCustomerName());
        select.eq(pageQueryMyTaskDto.getOrderId() != null && pageQueryMyTaskDto.getOrderId() > NumberConstant.ONE,
                Task::getOrderId, pageQueryMyTaskDto.getOrderId());
        Page<Task> page = new Page<>(pageQueryMyTaskDto.getCurrent(), pageQueryMyTaskDto.getSize());
        select.orderByDesc(Task::getAppointmentTime);
        IPage<Task> tasksPage = taskMapper.selectPage(page, select);
        List<Task> tasks = Optional.ofNullable(tasksPage.getRecords()).orElseGet(() -> {
            return Lists.newArrayList();
        });
        List<MyTaskListVo> myTaskListVos = TaskConverter.INSTANCE.toMyTaskDetailListVo(tasks);
        myTaskListVos.stream().forEach(myTaskVo -> {
            myTaskVo.setImgSrc(taskMapper.queryImageDetailByTaskId(myTaskVo.getId()));
        });
        return new ListRes<>(myTaskListVos, (int) tasksPage.getTotal());
    }

    /**
     * 抢单或完成任务
     *
     * @param doTaskDto
     * @return id
     */
    @Override
    public Long updateTask(DoTaskDto doTaskDto) {
        Optional<TaskOrderAction> orderAction = TaskOrderAction.ofAction(doTaskDto.getAction());
        Task task = checkTaskStatusFromDoTask(doTaskDto.getId(), orderAction.get());

        // 人工抢单
        if (orderAction.get() == TaskOrderAction.TASK_ORDER_ACCEPT) {
            grapTaskOrder(task, TaskOrderAction.TASK_ORDER_ACCEPT);
        } else { // 取消或者完成任务
            taskMapper.updateById(task);
            sentMsgGrapOrderResult(NumberConstant.ONE, task, orderAction.get(), TenantContext.getDomain(),
                    tokenUtil.getUidFromHeader());
        }
        //更新订单表状态
        UpdateOrderDto updateOrderDto=new UpdateOrderDto();
        updateOrderDto.setStatus(OrderTaskEnum.ofAction(orderAction.get().getAction()).get().getStatus());
        orderService.updateOrderStatus(updateOrderDto);

        return task.getId();
    }

    /**
     * 抢单或完成任务时验证当前的任务状态,并设置当前任务的状态
     *
     * @param taskId
     * @param orderAction 操作Action
     * @return {@link Task}
     */
    private Task checkTaskStatusFromDoTask(Long taskId, TaskOrderAction orderAction) {
        // 查询任务信息
        LambdaQueryWrapper<Task> selectQuery = Wrappers.lambdaQuery();
        selectQuery.eq(Task::getId, taskId);
        selectQuery.eq(Task::getDeleteFlag, DeletedFlagEnum.SERVICE_FLAGE_UNDELETED.getCode());
        Task taskFromDb = taskMapper.selectOne(selectQuery);
        TaskOrderAction taskStatusAction = TaskOrderAction.ofAction(taskFromDb.getTaskStatus()).get();

        // 验证任务是否存在
        Assert.notNull(taskFromDb, ErrorCode.TASK_NOT_EXIST.getCode(), ErrorCode.TASK_NOT_EXIST.getMessage());
        switch (orderAction) {
            case TASK_ORDER_CANCEL: // 取消操作，任务的状态必须是已接单
                Assert.isTrue(taskStatusAction == TaskOrderAction.TASK_ORDER_ACCEPT,
                        ErrorCode.TASK_UPDATE_NOT_PERMISSION_CANCEL.getCode(),
                        ErrorCode.TASK_UPDATE_NOT_PERMISSION_CANCEL.getMessage());
                break;
            case TASK_ORDER_FINISHED: // 任务完成操作，任务的状态必须是已接单
                Assert.isTrue(taskStatusAction == TaskOrderAction.TASK_ORDER_ACCEPT,
                        ErrorCode.TASK_UPDATE_NOT_PERMISSION_FINISHED.getCode(),
                        ErrorCode.TASK_UPDATE_NOT_PERMISSION_FINISHED.getMessage());
                break;
            case TASK_ORDER_ACCEPT: // 抢单操作，任务的状态必须是待抢单
                Assert.isTrue(taskStatusAction == TaskOrderAction.TASK_ORDER_WAITING,
                        ErrorCode.TASK_UPDATE_NOT_PERMISSION_GRAP.getCode(),
                        ErrorCode.TASK_UPDATE_NOT_PERMISSION_GRAP.getMessage());
                break;
            default: // 初始化任务的状态操作，默认非法操作
                Assert.isTrue(taskStatusAction == null, ErrorCode.TASK_UPDATE_NOT_PERMISSION.getCode(),
                        ErrorCode.TASK_UPDATE_NOT_PERMISSION.getMessage());
                break;
        }
        taskFromDb.setTaskStatus(orderAction.getAction());
        taskFromDb.setEmployeeId(tokenUtil.getUidFromHeader());
        taskFromDb.setEmployeeName(tokenUtil.getUserNameFromHeader());
        return taskFromDb;
    }

    /**
     * 多线程抢单任务，使用乐观锁
     *
     * @param orderAction
     */
    private void grapTaskOrder(Task task, TaskOrderAction orderAction) {
        if (threadPoolProperty.isEnable()) {
            if (threadPoolTaskExecutor == null) {
                threadPoolTaskExecutor = ApplicationContextUtil.getBean("threadPoolTaskExecutor");
            }
            threadPoolTaskExecutor.execute((() -> {
                doTaskGrap(task, orderAction);
            }));
        } else {
            Assert.isTrue(doTaskGrap(task, orderAction) == NumberConstant.ONE, ErrorCode.TASK_GRAB_FAILED.getCode(),
                    ErrorCode.TASK_GRAB_FAILED.getMessage());
        }
    }

    /**
     * 功能描述
     *
     * @author zWX1196307
     * @since 2022-09-22
     */
    private int doTaskGrap(Task task, TaskOrderAction orderAction) {
        String userId = tokenUtil.getUidFromHeader();
        String tenantDomain = TenantContext.getDomain();
        int result = taskMapper.grapTaskOrder(task);
        log.info("grapTaskOrder current thread:{},tenantDomain={},task.id={},result={}",
                Thread.currentThread().getName(), tenantDomain, task.getId(), result);
        sentMsgGrapOrderResult(result, task, orderAction, tenantDomain, userId);
        return result;
    }

    /**
     * 发送消息给订单中心和消息中心
     *
     * @param result      抢单结果
     * @param orderAction 工人操作行为 accept/finished/cancel
     */
    private void sentMsgGrapOrderResult(int result, Task taskOne, TaskOrderAction orderAction, String tenantDomain,
                                        String userId) {
        try {
            MessageServiceEntity messageServiceEntity = new MessageServiceEntity();
            String msgTempageOrder = "您好,【" + taskOne.getServiceName() + "】服务";
            String msgTempageCustomer = "您的订单【" + taskOne.getServiceName() + "】, 雇员【" + tokenUtil.getUserNameFromHeader() + "】";
            switch (orderAction) {
                case TASK_ORDER_FINISHED:
                    msgTempageOrder += ", 已完成任务!";
                    msgTempageCustomer += "已为您完成任务!";
                    messageServiceEntity.setTitle("任务已完成：" + taskOne.getServiceName());
                    break;
                case TASK_ORDER_CANCEL:
                    msgTempageOrder += ", 任务已取消!";
                    msgTempageCustomer += "已取消任务!";
                    messageServiceEntity.setTitle("任务已取消：" + taskOne.getServiceName());
                    break;
                default:
                    if (result == NumberConstant.ONE) {
                        msgTempageOrder += ", 抢单成功!";
                        msgTempageCustomer += "已接单!";
                        messageServiceEntity.setTitle("抢单成功：" + taskOne.getServiceName());
                    } else {
                        msgTempageOrder += ", 抢单失败!";
                        msgTempageCustomer = "";
                        messageServiceEntity.setTitle("抢单失败：" + taskOne.getServiceName());
                    }
            }
            Date dateNow = new Date();

            // 异步消息给订单中心 action:accept/finished/cancel
            TaskMessageEntity taskMessageEntity = new TaskMessageEntity();
            taskMessageEntity.setTime(dateNow);
            taskMessageEntity.setAction(orderAction.getAction());
            taskMessageEntity.setOrderId(taskOne.getOrderId());
            taskMessageEntity.setEmployeeId(taskOne.getEmployeeId());
            messageServiceUtil.sendMessageByAmqTopic(RabbitMqTopicConfig.ORDER_TASK_DO_TASK, taskMessageEntity,
                    tenantDomain);

            // 异步消息给消息中心，发送给工人消息
            messageServiceEntity.setMsg(msgTempageOrder);
            messageServiceEntity.setUserId(userId);
            messageServiceEntity.setTime(dateNow);
            messageServiceUtil.sendMessageByAmqTopic(RabbitMqTopicConfig.MESSAGE_TASK_ORDER, messageServiceEntity,
                    tenantDomain);
            //异步消息给消息中心，发送给用户消息
            if (StringUtils.isNotEmpty(msgTempageCustomer)) {
                messageServiceEntity.setMsg(msgTempageCustomer);
                messageServiceEntity.setUserId(taskOne.getCustomerId());
                messageServiceEntity.setTime(dateNow);
                messageServiceUtil.sendMessageByAmqTopic(RabbitMqTopicConfig.MESSAGE_TASK_ORDER, messageServiceEntity,
                        tenantDomain);
            }
        } catch (JsonProcessingException ex) {
            log.error("--->Capture exception info: ", ex);
        }
    }

    /**
     * 任务详情,除了用户名称和电话
     *
     * @param taskDetailDto 任务Id Dto
     * @return 任务详情
     */
    @Override
    public TaskDetailVo getTaskInfo(TaskDetailDto taskDetailDto) {
        LambdaQueryWrapper<Task> selectQuery = Wrappers.lambdaQuery();
        selectQuery.eq(Task::getId, taskDetailDto.getId());
        selectQuery.eq(Task::getDeleteFlag, DeletedFlagEnum.SERVICE_FLAGE_UNDELETED.getCode());
        Task taskOne = Optional.ofNullable(taskMapper.selectOne(selectQuery)).orElseGet(() -> {
            return new Task();
        });
        return TaskConverter.INSTANCE.toTaskDetailVo(taskOne);
    }

    /**
     * 任务表分页请求
     *
     * @param pageQueryTaskDto 分页请求Dto
     * @return 任务表列表
     */
    @Override
    public ListRes<TaskPageListVo> pageQueryTasks(PageQueryTaskDto pageQueryTaskDto) {
        LambdaQueryWrapper<Task> select = Wrappers.lambdaQuery();
        select.eq(Task::getDeleteFlag, DeletedFlagEnum.SERVICE_FLAGE_UNDELETED.getCode());
        select.eq(StringUtils.isNotEmpty(pageQueryTaskDto.getTaskStatus()), Task::getTaskStatus,
                pageQueryTaskDto.getTaskStatus());
        select.eq(StringUtils.isEmpty(pageQueryTaskDto.getTaskStatus()), Task::getTaskStatus,
                TaskOrderAction.TASK_ORDER_WAITING.getAction());
        select.like(StringUtils.isNotEmpty(pageQueryTaskDto.getCustomerName()), Task::getCustomerName,
                pageQueryTaskDto.getCustomerName());
        select.eq(StringUtils.isNotEmpty(pageQueryTaskDto.getEmployeeId()), Task::getEmployeeId,
                pageQueryTaskDto.getEmployeeId());
        select.eq(pageQueryTaskDto.getOrderId() != null, Task::getOrderId, pageQueryTaskDto.getOrderId());
        Page<Task> page = new Page<>(pageQueryTaskDto.getCurrent(), pageQueryTaskDto.getSize());
        select.orderByDesc(Task::getAppointmentTime);
        IPage<Task> tasksPage = taskMapper.selectPage(page, select);
        List<Task> tasks = Optional.ofNullable(tasksPage.getRecords()).orElseGet(() -> {
            return Lists.newArrayList();
        });
        List<TaskPageListVo> taskPageListVos = TaskConverter.INSTANCE.toTaskPageListVo(tasks);
        taskPageListVos.stream().forEach(listVo -> {
            listVo.setImgSrc(taskMapper.queryImageDetailByTaskId(listVo.getId()));
        });

        return new ListRes<>(taskPageListVos, (int) tasksPage.getTotal());
    }
}